﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Serialization;

namespace FrameWork.Core.Utils
{
    /// <summary>
    /// xml帮助类
    /// </summary>
    public class XMLHelper
    {
        public static void ToXmlDocument(string xmlstr, string filePath)
        {
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.LoadXml(xmlstr);
            doc.Save(filePath);
        }

        /// <summary>
        /// 带属性的xml字符串转对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="xmlStr"></param>
        /// <returns></returns>
        public static List<T> DeserializeFromXmlToModelOnAttribute<T>(string xmlStr, string xpath) where T : new()
        {
            List<T> list = new List<T>();

            XmlDocument xmlDocument = new XmlDocument();
            xmlDocument.LoadXml(xmlStr);
            foreach (XmlElement book in xmlDocument.SelectNodes(xpath))
            {
                list.Add(XmlElementToModelOnAttribute<T>(book));
            }
            return list;
        }

        public static T XmlElementToModelOnAttribute<T>(XmlElement element) where T : new()
        {
            var t = new T();
            PropertyInfo[] pros = t.GetType().GetProperties();
            foreach (PropertyInfo pi in pros)
            {
                if (pi.PropertyType.BaseType.Name == "Array")
                {
                    Type t1 = pi.PropertyType.GetElementType();
                    if (element.SelectNodes(pi.Name).Count > 0)
                    {
                        Array tarray = Array.CreateInstance(t1, element.SelectNodes(pi.Name).Count);
                        XMLHelper xml = new XMLHelper();
                        Type workerType = typeof(XMLHelper);
                        MethodInfo staticDoWorkMethod = workerType.GetMethod("XmlElementToModelOnAttribute");
                        MethodInfo curMethod = staticDoWorkMethod.MakeGenericMethod(t1);
                        for (int i = 0; i < element.SelectNodes(pi.Name).Count; i++)
                        {
                            var tt = System.Activator.CreateInstance(t1);
                            tt = curMethod.Invoke(xml, new object[] { (XmlElement)element.SelectNodes(pi.Name)[i] });
                            tarray.SetValue(tt, i);
                        }
                        pi.SetValue(t, tarray);
                    }
                }
                else
                {
                    XmlAttribute attribute = null;
                    if (element.HasAttribute(pi.Name))
                    {
                        attribute = element.Attributes[pi.Name];
                        if (pi.PropertyType.Name == "Byte")
                        {
                            byte n = 0;
                            if (byte.TryParse(attribute.Value, out n))
                                pi.SetValue(t, n);
                        }
                        else if (pi.PropertyType.Name == "SByte")
                        {
                            sbyte n = 0;
                            if (sbyte.TryParse(attribute.Value, out n))
                                pi.SetValue(t, n);
                        }
                        else if (pi.PropertyType.Name == "Decimal")
                        {
                            decimal n = 0;
                            if (decimal.TryParse(attribute.Value, out n))
                                pi.SetValue(t, n);
                        }
                        else if (pi.PropertyType.Name == "Double")
                        {
                            double n = 0;
                            if (double.TryParse(attribute.Value, out n))
                                pi.SetValue(t, n);
                        }
                        else
                        {
                            pi.SetValue(t, attribute.Value);
                        }


                    }
                }
            }
            return t;
        }
        /// <summary>     
        /// 读取Xml文件内容反序列化为指定的对象  
        /// </summary>    
        /// <param name="filePath">Xml文件的位置（绝对路径）</param>  
        /// <returns></returns>    
        public static T DeserializeFromXml<T>(string filePath)
        {
            try
            {
                if (!File.Exists(filePath))
                    throw new ArgumentNullException(filePath + " not Exists");
                using (StreamReader reader = new StreamReader(filePath))
                {
                    XmlSerializer xs = new XmlSerializer(typeof(T));
                    T ret = (T)xs.Deserialize(reader);
                    return ret;
                }
            }
            catch (Exception ex)
            {
                return default(T);
            }
        }
        /// <summary>
        /// 实体转xml文档
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string XmlSerialize<T>(T obj)
        {
            using (System.IO.StringWriter sw = new StringWriter())
            {
                Type t = obj.GetType();
                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
                serializer.Serialize(sw, obj);
                sw.Close();
                return sw.ToString();
            }
        }




        public static string FormatXML(string XMLstring)
        {
            XmlDocument xmlDocument = GetXmlDocument(XMLstring);
            return ConvertXmlDocumentTostring(xmlDocument);
        }

        public static string ConvertXmlDocumentTostring(XmlDocument xmlDocument)
        {
            MemoryStream memoryStream = new MemoryStream();
            XmlTextWriter writer = new XmlTextWriter(memoryStream, null)
            {
                Formatting = Formatting.Indented//抹序
            };
            xmlDocument.Save(writer);
            StreamReader streamReader = new StreamReader(memoryStream);
            memoryStream.Position = 0;
            string xmlString = streamReader.ReadToEnd();
            streamReader.Close();
            memoryStream.Close();
            return xmlString;
        }

        public static XmlDocument GetXmlDocument(string xmlString)
        {
            XmlDocument document = new XmlDocument();
            document.LoadXml(xmlString);
            return document;

        }


        /// <summary>
        /// 对xml节点进行换行，格式化对齐操作
        /// </summary>
        /// <param name="srcXml"></param>
        /// <returns></returns>
        public static string FormatXml(string srcXml)
        {
            string formattedXml = IndentedFormat(IndentedFormat(srcXml).Replace("><", ">\r\n<"));
            return formattedXml;
        }

        /// <summary>
        /// 对XML字符串进行换行缩进，格式化
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        private static string IndentedFormat(string xml)
        {
            string indentedText = string.Empty;
            try
            {
                XmlTextReader reader = new XmlTextReader(new StringReader(xml));
                reader.WhitespaceHandling = WhitespaceHandling.None;

                StringWriter indentedXmlWriter = new StringWriter();
                XmlTextWriter writer = CreateXmlTextWriter(indentedXmlWriter);
                writer.WriteNode(reader, false);
                writer.Flush();

                indentedText = indentedXmlWriter.ToString();
            }
            catch (Exception)
            {
                indentedText = xml;
            }
            return indentedText;
        }

        /// <summary>
        /// 写入四个缩进字符【空格】
        /// </summary>
        /// <param name="textWriter"></param>
        /// <returns></returns>
        private static XmlTextWriter CreateXmlTextWriter(TextWriter textWriter)
        {
            XmlTextWriter writer = new XmlTextWriter(textWriter);
            //将Tab转化为4个空格
            bool convertTabsToSpaces = true;
            if (convertTabsToSpaces)
            {
                writer.Indentation = 4;
                writer.IndentChar = ' ';
            }
            else
            {
                writer.Indentation = 1;
                writer.IndentChar = '\t';
            }
            writer.Formatting = Formatting.Indented;
            return writer;
        }
    }
}
